/*
Copyright (c) 2025 HeZongLun
NahidaProject is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan
PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/

#pragma once

#ifdef _WIN32
#define ExportSymbol  __declspec(dllexport)
#else
#define ExportSymbol
#endif

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

namespace NahidaProject {
	class ExportSymbol SnowFlake {
	private:
		static constexpr int64_t kEpoch = 1640995200000LL;
		static constexpr int kTimestampBits = 41;
		static constexpr int kMachineIdBits = 10;
		static constexpr int kSequenceBits = 12;

		static constexpr int64_t kMaxMachineId = (1LL << kMachineIdBits) - 1;
		static constexpr int64_t kMaxSequence = (1LL << kSequenceBits) - 1;

		static constexpr int kMachineIdShift = kSequenceBits;
		static constexpr int kTimestampShift = kSequenceBits + kMachineIdBits;

		int64_t machineId;
		int64_t lastTimeStamp;
		int64_t sequence;
		std::mutex mutex;

		int64_t GetCurrentTimeStamp();
		int64_t WaitNextMillis(int64_t lastTimeStamp);

	public:
		SnowFlake(int64_t machineId) : machineId(machineId), lastTimeStamp(0), sequence(0) {
			if (machineId < 0 || machineId > kMaxMachineId) {
				throw std::invalid_argument("Machine ID out of range.");
			}
		}

		int64_t NextId();
	};
}